package ichubconfig

import (
	"gitee.com/ichub/goconfig/common/base/baseconfig"
	"gitee.com/ichub/goconfig/common/base/baseconfig/configdto"
	"gitee.com/ichub/goconfig/common/base/baseconsts"
	"gitee.com/ichub/goconfig/common/base/baseutils/fileutils"
	"gitee.com/ichub/goconfig/common/base/baseutils/goutils"
	"gitee.com/ichub/goconfig/common/base/baseutils/jsonutils"
	"gitee.com/ichub/goconfig/common/base/encrypt"
	"gitee.com/ichub/goconfig/common/ichublog"
	"github.com/duke-git/lancet/system"
	"github.com/gogf/gf/util/gconv"
	"github.com/jinzhu/copier"
	"github.com/spf13/viper"
	"os"
	"strings"
	"sync"
)

/*
	@Title    文件名称: ichub_config.go
	@Description  描述:  配置文件

	@Author  作者: leijianming@163.com  时间(2024-02-22 22:38:21)
	@Update  作者: leijianming@163.com  时间(2024-02-21 22:38:21)
*/

// commonfilename
const ConfigfileAppCommon = "/config/app-common.yml"
const ConfigfileAppEnv = "/config/app-env.yml"
const ConfigfileApp = "/config/app.yml"

var lock sync.Mutex

type IchubConfig struct {
	configdto.IchubClientDto
	// 区分规则引擎, db和es引擎 WebClientType int

	Env      string `json:"env"`
	BasePath string `json:"base_path"`

	EnvConfigFile  string `json:"env_config_file"`
	ConfigFile     string `json:"config_file"`
	RealConfigFile string `json:"real_config_file"`
	Software       baseconfig.SoftwareDto
	Gocenter       baseconfig.GocenterDto `json:"gocenter"`

	Etcd struct {
		Server struct {
			Hosturl string `json:"hosturl"`
		}
	}

	Rpc struct {
		ServerName string `json:"server_name"`
		ServerPort int    `json:"server_port"`
		ClientName string `json:"client_name"`
	}

	Web struct {
		Server struct {
			Name string `json:"name"`
			Port int    `json:"port"`
		}
		Client struct {
			Name       string `json:"name"`
			TestUrl    string `json:"test_url"`
			WebTimeout string `json:"web_timeout"`
		}
		Swagger struct {
			Host     string `json:"host"`
			BasePath string `json:"base_path"`
			Version  string `json:"version"`
			Title    string `json:"title"`
			Enable   string `json:"enable"`
		}
	}

	Datasource struct {
		Dbtype string `json:"dbtype"`
		Dbname string `json:"dbname"`
		Host   string `json:"host"`
		Port   string `json:"port"`

		Username string `json:"username"`
		Password string `json:"password"`
		Sslmode  string `json:"sslmode"`
		Charset  string `json:"charset"`
	}

	Redis struct {
		Db       int    `json:"db"`
		Addr     string `json:"addr"`
		Password string `json:"password"`
	} `json:"redis"`

	Es struct {
		Url      string `json:"url"`
		Username string `json:"username,omitempty"`
		Password string `json:"password,omitempty"`
	}
	Mysql struct {
		Dbtype string `json:"dbtype"`
		Dbname string `json:"dbname"`
		Host   string `json:"host"`
		Port   string `json:"port"`

		Username string `json:"username"`
		Password string `json:"password"`
		Sslmode  string `json:"sslmode"`
		Charset  string `json:"charset"`
	}

	Gorm    baseconfig.GormClientDto
	Factroy baseconfig.FactroyClientDto
	Natscli baseconfig.NatsClientDto `json:"natscli"`

	Gateway baseconfig.GatewayDto
	viper   *viper.Viper `json:"-"`
}

func New(configFile string) *IchubConfig {
	var ichubConfig = &IchubConfig{
		ConfigFile: configFile,
	}
	ichubConfig.InitProxy(ichubConfig)
	return ichubConfig
}
func Default() *IchubConfig {
	return New(ConfigfileApp)
}

func NewIchubConfig() *IchubConfig {
	return New(ConfigfileApp)
}

func (ic *IchubConfig) Log() {
	ichublog.Log(ic)
}
func (ic *IchubConfig) Single() bool {
	return true
}
func (ic *IchubConfig) FullFileName() string {
	if len(ic.BasePath) == 0 {
		ic.BasePath = os.Getenv(baseconsts.IchubBasePath)
	}
	return ic.BasePath + ic.ParseRealFileName()
}

// 解析真正的环境文件名称
func (ic *IchubConfig) ParseRealFileName() string {

	var files = strings.Split(ic.ConfigFile, ".")
	var env = ""
	if len(ic.Env) > 0 {
		env = "-" + ic.Env
	}
	ic.RealConfigFile = files[0] + env + "." + files[1]

	return ic.RealConfigFile
}

func (ic *IchubConfig) EnvFileName() string {
	ic.EnvConfigFile = baseconsts.ConfigfileAppEnv
	if len(ic.BasePath) == 0 {
		ic.BasePath = os.Getenv(baseconsts.IchubBasePath)
	}
	return ic.BasePath + ic.EnvConfigFile
}

func (ic *IchubConfig) LogFileName() {
	goutils.Info(ic.FullFileName())
}

func (ic *IchubConfig) CheckFileExist() bool {

	return fileutils.CheckFileExist(ic.FullFileName())

}
func (ic *IchubConfig) CheckEnvFileExist() bool {

	return fileutils.CheckFileExist(ic.EnvFileName())

}
func (ic *IchubConfig) SetDefaultBasePath(basepath string) {
	if len(basepath) == 0 {
		basepath = system.GetOsEnv(baseconsts.IchubBasePath)
	}
	if len(basepath) == 0 {
		basepath = fileutils.GetCurPath()
	}

	if ic.ConfigFile == "" {
		ic.ConfigFile = ConfigfileApp
	}
	ic.BasePath = basepath
}
func (ic *IchubConfig) ReadConfigEnv() string {

	if !ic.CheckEnvFileExist() {
		goutils.Warning("file not exist!" + ic.EnvFileName())
	}

	viperInst := viper.New()
	viperInst.SetConfigType("yaml")
	viperInst.SetConfigFile(ic.EnvFileName())

	err := viperInst.ReadInConfig()
	if err != nil {
		goutils.Error(err)
		return ""
	}
	err = viperInst.Unmarshal(ic)
	if err != nil {
		goutils.Error(err)
		return ""
	}
	goutils.Info("ReadConfigEnv=", ic.Env)

	ic.Env = ic.ParseValue("env", ic.Env)
	if ic.Env == baseconsts.ENV_DEFAULT {
		ic.Env = baseconsts.ENV_EMPTY
	}

	return ic.Env

}
func (ic *IchubConfig) ReadConfig(basePath string) {
	if ic.viper != nil {
		return
	}

	ic.SetDefaultBasePath(basePath)
	ic.ReadConfigEnv()
	if !ic.CheckFileExist() {
		goutils.Error("file not exist!" + ic.FullFileName())
		panic("file not exist!" + ic.FullFileName())
	}

	goutils.Info(ic.FullFileName())
	viperInst := viper.New()
	viperInst.SetConfigType("yaml")
	viperInst.SetConfigFile(ic.FullFileName())
	ic.viper = viperInst
	err := viperInst.ReadInConfig()
	if err != nil {
		goutils.Error(err)
		return
	}
	err = viperInst.Unmarshal(ic)
	if err != nil {
		goutils.Error(err)
	}
	ic.Parse()

}

func (ic *IchubConfig) SetOsEnv(key, value string) *IchubConfig {
	system.SetOsEnv(key, value)
	return ic
}
func (ic *IchubConfig) ReadIf() *IchubConfig {
	lock.Lock()
	defer lock.Unlock()
	if ic.viper == nil {
		ic.Read()
	}
	return ic
}

func (ic *IchubConfig) Read() *IchubConfig {
	lock.Lock()
	defer lock.Unlock()
	if ic.viper != nil {
		return ic
	}

	var basepath = system.GetOsEnv(baseconsts.IchubBasePath)
	if len(basepath) == 0 {
		basepath = fileutils.GetCurPath()
	}
	ic.ReadConfig(basepath)

	return ic

}
func (ic *IchubConfig) ReadNats() *baseconfig.NatsClientDto {

	ic.Read()
	ic.Natscli.InitProxy(ic.Natscli)
	return &ic.Natscli
}

func (ic *IchubConfig) ReadMap(pathkey string) map[string]interface{} {
	ic.Read()
	return ic.viper.GetStringMap(pathkey)
}

func (ic *IchubConfig) ReadMapSlice(pathkey string) map[string][]string {
	ic.Read()
	return ic.viper.GetStringMapStringSlice(pathkey)
}

func (ic *IchubConfig) ReadIchubFactroy() baseconfig.FactroyClientDto {

	ic.Read()
	ic.Factroy.InitProxy(ic.Factroy)
	return ic.Factroy
}

func (ic *IchubConfig) ReadInt(pathkey string) int {
	ic.Read()
	return ic.viper.GetInt(pathkey)
}

func (ic *IchubConfig) ReadString(pathkey string) string {
	ic.Read()
	var s = ic.viper.GetString(pathkey)
	s = ic.ParseValue("s", s)
	return s
}

func (ic *IchubConfig) ReadStringSlice(pathkey string) []string {
	ic.Read()
	var s = ic.viper.GetStringSlice(pathkey)
	//s = ic.ParseValue("s", s)
	return s
}

// "key1.key"
func (ic *IchubConfig) ReadStruct(pathkey string, object interface{}) {

	var ichubMap = ic.ReadMap(pathkey)
	jsonutils.FromJson(jsonutils.ToJsonPretty(ichubMap), object)

	ic.ParseSome(object)
}

func (ic *IchubConfig) ReadGocenter() *baseconfig.GocenterDto {

	ic.Read()
	ic.Gocenter.InitProxy(&ic.Gocenter)
	return &ic.Gocenter
}

func (ic *IchubConfig) ReadIchubDb() *baseconfig.DbClientDto {

	ic.Read()
	if ic.Gorm.DbType == baseconsts.DB_TYPE_MYSQL {
		return ic.ReadIchubMysql()
	}
	if ic.Gorm.DbType == baseconsts.DB_TYPE_COCKROACH {
		return ic.ReadIchubDatasource()
	}
	return ic.ReadIchubDatasource()
}

func (ic *IchubConfig) ReadIchubDatasource() *baseconfig.DbClientDto {

	ic.Read()
	var dbClientDto = baseconfig.NewDbClientDto()
	copier.Copy(dbClientDto, &ic.Datasource)

	dbClientDto.GormClient = ic.ReadIchubGorm()
	dbClientDto.Parse()
	return dbClientDto //.(*baseconfig.DbClientDto)
}

func (ic *IchubConfig) ReadIchubMysql() *baseconfig.DbClientDto {

	ic.Read()
	var dbClientDto = baseconfig.NewDbClientDto()
	copier.Copy(dbClientDto, &ic.Mysql)
	dbClientDto.GormClient = ic.ReadIchubGorm()

	dbClientDto.Parse()
	return dbClientDto //.(*baseconfig.DbClientDto)
}

func (ic *IchubConfig) ReadIchubGorm() *baseconfig.GormClientDto {

	ic.Read()
	var dto = baseconfig.NewGormClientDto()
	dto.CopyWithOption(ic.Gorm)
	return dto.Parse().(*baseconfig.GormClientDto)
}

func (ic *IchubConfig) ReadIchubRpc() *baseconfig.RpcServerDto {

	ic.Read()
	var dto = &baseconfig.RpcServerDto{
		EtcdHost:   ic.Etcd.Server.Hosturl,
		ServerName: ic.Rpc.ServerName,
		ServerPort: ic.Rpc.ServerPort,
		ClientName: ic.Rpc.ClientName,
	}
	return dto.Parse()
}

func (ic *IchubConfig) ReadIchubEs() *baseconfig.ElasticClientDto {

	ic.Read()
	var dto = &baseconfig.ElasticClientDto{
		URL:      ic.Es.Url,
		Username: ic.Es.Username,
		Password: ic.Es.Password,
	}
	return dto.Parse()
}
func (ic *IchubConfig) ReadIchubRedis() *baseconfig.RedisClientDto {

	ic.Read()
	var dto = &baseconfig.RedisClientDto{
		Addr:     ic.Redis.Addr,
		Password: ic.Redis.Password,
		DB:       ic.Redis.Db,
	}
	dto.InitProxy(dto)
	return dto.Parse()
}
func (ic *IchubConfig) ReadIchubWebServer() (serverDto *baseconfig.WebServerDto) {

	ic.Read()
	serverDto = baseconfig.NewWebServerDto()

	serverDto.ServerName = ic.Web.Server.Name
	serverDto.ServerPort = ic.Web.Server.Port
	serverDto.EtcdHost = ic.Etcd.Server.Hosturl
	return serverDto.Parse()
}

func (ic *IchubConfig) ReadIchubWebClient() (clientDto *baseconfig.WebClientDto) {

	ic.Read()
	clientDto = baseconfig.NewWebClientDto()
	clientDto.EtcdHost = ic.Etcd.Server.Hosturl
	clientDto.ServerName = ic.Web.Client.Name
	clientDto.TestUrl = ic.Web.Client.TestUrl
	clientDto.WebTimeout = ic.Web.Client.WebTimeout

	return clientDto
}

func (ic *IchubConfig) ReadIchubCommon() *IchubConfig {

	ic.ConfigFile = ConfigfileAppCommon
	ic.Read()
	return ic
}

func (ic *IchubConfig) ReadFactroy() baseconfig.FactroyClientDto {

	return ic.ReadIchubFactroy()
}

func (ic *IchubConfig) ReadGateway() *baseconfig.GatewayDto {

	ic.Read()
	ic.InitProxy(ic)
	return ic.Gateway.ToMap()
}
func (ic *IchubConfig) ReadWebSwagger() *baseconfig.SwaggerClientDto {

	ic.Read()
	var swagger = baseconfig.NewSwaggerClientDto()

	swagger.Host = ic.Web.Swagger.Host
	swagger.BasePath = ic.Web.Swagger.BasePath
	swagger.Version = ic.Web.Swagger.Version
	swagger.Title = ic.Web.Swagger.Title
	swagger.Enable = ic.Web.Swagger.Enable

	swagger.Parse()
	return swagger
}
func (ic *IchubConfig) RegisterEncDec(encdec encrypt.IEncDec) *IchubConfig {

	ic.viper = nil
	configdto.Context.RegisterEncDec(encdec)
	return ic
}
func (ic *IchubConfig) ReadVar(pathkey string) interface{} {
	ic.Read()
	return ic.ParseValue(pathkey, gconv.String(ic.viper.Get(pathkey)))
}
func (ic *IchubConfig) ReadVar2Rpc(key string) *baseconfig.RpcServerDto {
	ic.Read()
	var value = ic.viper.Get(key)
	var rpc = baseconfig.NewRpcServerDto()
	var err = jsonutils.FromJson(jsonutils.ToJsonPretty(value), rpc)
	if err != nil {
		goutils.Error(err)
	}
	rpc.EtcdHost = ic.Etcd.Server.Hosturl
	rpc.Parse()
	return rpc
}
func (ic *IchubConfig) ReadVar2WebClient(key string) *baseconfig.WebClientDto {
	ic.Read()
	var value = ic.viper.Get(key)
	var dto = baseconfig.NewWebClientDto()

	var err = jsonutils.FromJson(jsonutils.ToJsonPretty(value), dto)
	if err != nil {
		goutils.Error(err)
	}
	dto.EtcdHost = ic.Etcd.Server.Hosturl

	dto.Parse()
	return dto
}

func (ic *IchubConfig) ReadConfigFile() string {

	//goutils.Info(ichubConfig.FullFileName())
	var rootdir = fileutils.FindRootDir()
	var file = rootdir + ic.ParseRealFileName()

	return file
}
func (ic *IchubConfig) ChangeDbType(dbtype string) string {
	var back_dbtype = ic.ReadIchubDb().Dbtype
	ic.Gorm.DbType = dbtype
	return back_dbtype
}
func (ic *IchubConfig) ReadConfigBase(env ...string) {

	lock.Lock()
	defer lock.Unlock()

	ic.BasePath = fileutils.FindRootDir()

	if len(env) == 0 {
		ic.ReadConfigEnv()
	} else {
		ic.Env = env[0]
	}
	if !ic.CheckFileExist() {
		goutils.Error("file not exist!" + ic.FullFileName())
		panic("file not exist!" + ic.FullFileName())
	}

	viperInst := viper.New()
	viperInst.SetConfigType("yaml")
	viperInst.SetConfigFile(ic.FullFileName())
	ic.viper = viperInst
	err := viperInst.ReadInConfig()
	if err != nil {
		goutils.Error(err)
		return
	}
	err = viperInst.Unmarshal(ic)
	if err != nil {
		goutils.Error(err)
	}
	ic.Parse()
}
func (ic *IchubConfig) ReadDefault() *IchubConfig {

	ic.ReadConfigBase()
	return ic
}
func (ic *IchubConfig) ReadDev() *IchubConfig {

	ic.ReadConfigBase(baseconsts.ENV_DEV)
	return ic
}
func (ic *IchubConfig) ReadTest() *IchubConfig {

	ic.ReadConfigBase(baseconsts.ENV_TEST)
	return ic
}

func (ic *IchubConfig) ReadMaster() *IchubConfig {

	ic.ReadConfigBase(baseconsts.ENV_MASTER)
	return ic
}
func (ic *IchubConfig) ReadRelease() *IchubConfig {

	ic.ReadConfigBase(baseconsts.ENV_RELEASE)
	return ic
}
